package com.xunshibao.tutor.search;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.BooleanClause;
import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.store.RAMDirectory;
import org.apache.lucene.util.Version;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.xunshibao.core.page.Pagination;
import com.xunshibao.tutor.po.ext.TutorInfoExt;
import com.xunshibao.tutor.user.service.TutorInfoServiceImpl;

@Service
public class SearchServiceImpl {
	private String indexPath = "c:/index";

	@Autowired
	private TutorInfoServiceImpl infoService;

	public int indexTutor() {
		int pageNo = 1;
		Pagination page = infoService.list(pageNo, 10);
		pageNo++;

		List<TutorInfoExt> list = (List<TutorInfoExt>) page.getList();

		if (list != null && !list.isEmpty()) {
			FSDirectory fsDir;
			IndexWriterConfig fsConfig;
			IndexWriter fsWriter;

			File path = new File(indexPath);
			if (path.exists() && path.isDirectory()) {
				File[] files = path.listFiles();
				for (File f : files) {
					f.delete();
				}
				path.mkdirs();
			} else {
				path.mkdirs();
			}
			try {
				fsDir = FSDirectory.open(path);
				fsConfig = new IndexWriterConfig(Version.LUCENE_31,
						new StandardAnalyzer(Version.LUCENE_31));
				fsWriter = new IndexWriter(fsDir, fsConfig);
			} catch (IOException e1) {
				e1.printStackTrace();
				return -1;
			}

			TutorInfoSearchItem item;
			String[] area;
			String[] areaName;

			do {
				indexTutor(list, fsWriter);
				page = infoService.list(pageNo, 10);
				pageNo++;
				list = (List<TutorInfoExt>) page.getList();
			} while (list == null || list.isEmpty());

			try {
				fsWriter.optimize(true);
				fsWriter.commit();
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				try {
					fsWriter.close();
				} catch (Exception e1) {
					// TODO Auto-generated catch block
					e1.printStackTrace();
				}
			}
		}
		return 0;
	}

	public int indexTutor(List<TutorInfoExt> items, IndexWriter fsWriter) {

		if (items != null) {
			RAMDirectory ramDir = new RAMDirectory();
			IndexWriterConfig ramConfig;
			IndexWriter ramWriter;
			try {
				ramConfig = new IndexWriterConfig(Version.LUCENE_31,
						new StandardAnalyzer(Version.LUCENE_31));
				ramWriter = new IndexWriter(ramDir, ramConfig);
			} catch (Exception e1) {
				e1.printStackTrace(); // TODO
				return -1;// 创建索引writer失败
			}
			int i = 0;
			for (TutorInfoExt item : items) {
				i++;
				try {
					buildDoc(item, ramWriter);
					if (i % 100 == 0) {
						i = 0;
						ramWriter.close();
						copyIndexes(fsWriter, ramDir);
						ramConfig = new IndexWriterConfig(Version.LUCENE_31,
								new StandardAnalyzer(Version.LUCENE_31));
						ramWriter = new IndexWriter(ramDir, ramConfig);
					}

				} catch (Exception e) {
					e.printStackTrace();
				}
			}
			try {
				ramWriter.close();
				copyIndexes(fsWriter, ramDir);
			} catch (Exception e) {
				e.printStackTrace();
			}

		}

		return 0;
	}

	private void copyIndexes(IndexWriter fsWriter, RAMDirectory ramDir) {
		try {
			fsWriter.addIndexes(new Directory[] { ramDir });
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	private void buildDoc(TutorInfoExt item, IndexWriter writer)
			throws Exception {
		Document doc = new Document();
		String area[] = item.getArea().split(":");
		String areaName[] = item.getAreaName().split("-");

		// 所在省份
		Field field = new Field("p", area[0], Field.Store.NO,
				Field.Index.NOT_ANALYZED_NO_NORMS);
		doc.add(field);
		field = new Field("pn", areaName[0], Field.Store.YES, Field.Index.NO);
		doc.add(field);

		// 所在城市
		field = new Field("c", area[1], Field.Store.NO,
				Field.Index.NOT_ANALYZED_NO_NORMS);
		doc.add(field);
		field = new Field("cn", areaName[1], Field.Store.YES, Field.Index.NO);
		doc.add(field);

		// 所在地区名称、编码
		if (area.length == 3) {
			field = new Field("d", area[2], Field.Store.NO,
					Field.Index.NOT_ANALYZED_NO_NORMS);
			doc.add(field);
			field = new Field("dn", areaName[2], Field.Store.YES,
					Field.Index.NO);
			doc.add(field);
		} else {
			field = new Field("d", "", Field.Store.NO,
					Field.Index.NOT_ANALYZED_NO_NORMS);
			doc.add(field);
			field = new Field("dn", "", Field.Store.YES, Field.Index.NO);
			doc.add(field);
		}

		// 学校类型
		field = new Field("st", item.getTp() + "", Field.Store.YES,
				Field.Index.NOT_ANALYZED_NO_NORMS);
		doc.add(field);

		// 学校名称、编码
		field = new Field("sn", item.getSchoolName(), Field.Store.YES,
				Field.Index.NO);
		doc.add(field);
		field = new Field("s", item.getSchool() + "", Field.Store.NO,
				Field.Index.NOT_ANALYZED_NO_NORMS);
		doc.add(field);

		// 教师类型
		// field = new Field("t", item.getTeacherType(), Field.Store.YES,
		// Field.Index.NOT_ANALYZED_NO_NORMS);
		// doc.add(field);

		// 科目
		field = new Field("sub", item.getSubid() + "", Field.Store.YES,
				Field.Index.NOT_ANALYZED_NO_NORMS);
		doc.add(field);

		// 上课时间
		field = new Field("sch", item.getSchedule(), Field.Store.YES,
				Field.Index.NOT_ANALYZED_NO_NORMS);
		doc.add(field);

		// 性别
		field = new Field("g", item.getGender(), Field.Store.YES,
				Field.Index.NOT_ANALYZED_NO_NORMS);
		doc.add(field);

		// 姓名
		field = new Field("n", item.getUname(), Field.Store.YES,
				Field.Index.ANALYZED);
		doc.add(field);

		field = new Field("id", item.getId() + "", Field.Store.YES,
				Field.Index.NOT_ANALYZED_NO_NORMS);
		doc.add(field);

		writer.addDocument(doc);
	}

	public List<TutorInfoSearchItem> searchTutorInfo(Map<String, String> criteria) {
		FSDirectory fsDir;
		IndexSearcher searcher;
		try {
			fsDir = FSDirectory.open(new File(indexPath));
			searcher = new IndexSearcher(fsDir, true);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return null;
		}

		try {
			BooleanQuery searchQuery = new BooleanQuery();
			Iterator<Entry<String, String>> iter = criteria.entrySet()
					.iterator();
			Entry<String, String> entry;
			Query query;

			while (iter.hasNext()) {
				entry = iter.next();
				query = new TermQuery(
						new Term(entry.getKey(), entry.getValue()));
				searchQuery.add(query, BooleanClause.Occur.MUST);
			}

			TopDocs matches = searcher.search(searchQuery, 10);
			ScoreDoc[] docs = matches.scoreDocs;

			if (docs != null) {
				Document doc;
				TutorInfoSearchItem item;
				List<TutorInfoSearchItem> items = new ArrayList<TutorInfoSearchItem>();
				for (ScoreDoc d : docs) {
					doc = searcher.doc(d.doc);
					item = new TutorInfoSearchItem(doc.get("id"), doc.get("g"),
							doc.get("n"), doc.get("sch"), doc.get("sn"),
							doc.get("dn"), doc.get("cn"), doc.get("pn"),
							doc.get("sub"), doc.get("st"));
					items.add(item);
				}
				return items;
			}

		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
	}

	public static void main(String[] args) {
		SearchServiceImpl search = new SearchServiceImpl();
		search.indexTutor();

//		Map<String, String> criteria = new HashMap<String, String>();
//		criteria.put("g", "0");
//		criteria.put("sub", "46");
//		List<TutorInfoSearchItem>  items = search.searchTutorInfo(criteria);
//		if(items != null) {
//			for(TutorInfoSearchItem item : items) {
//				System.out.println(item.getName() + "-" + item.getArea() + "-" + item.getId() + "-" + item.getSubject());
//			}
//		}
	}
}
